package com.NetWork.Netty;

import com.Gameplay.character.Role.parentRole;
import com.NetWork.Decoder.PlayerDecoder;
import com.NetWork.Encoder.PlayerEncoder;
import com.NetWork.PlayerStatus.PlayerStatus;
import io.netty.bootstrap.Bootstrap;


import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;

import java.util.concurrent.ConcurrentLinkedQueue;


public class Client {
    private static EventLoopGroup clientGroup;
    public static boolean isConnected = false;
    private static Channel channel;
    public static final ConcurrentLinkedQueue<PlayerStatus> p2States = new ConcurrentLinkedQueue<>();
    public static final ConcurrentLinkedQueue<PlayerStatus> p1States = new ConcurrentLinkedQueue<>();
    public static Bootstrap bootstrap;

    public static void startClient() {
        //实例化事件工作组，本质上是线程池，可以处理管道中的各种任务，且任务的执行为异步非阻塞执行
        clientGroup = new NioEventLoopGroup();
        //启动项，启动客户端，为客户端提供各种参数
        bootstrap = new Bootstrap();
        //设置客户端的工作组
        bootstrap.group(clientGroup)
                .channel(NioSocketChannel.class)//设置普通非阻塞通道作为连接通道
                .option(ChannelOption.TCP_NODELAY, true)
                .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                .handler(new ChannelInitializer<SocketChannel>() {//初始化处理器用于正式处理数据
                    //初始化管道，socket网络嵌套字
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline()//获取连接的数据管道 并给其添加Handler 就像工厂流水线那样处理服务端发来的数据
                                //Encoder
                                .addLast(new StringEncoder(CharsetUtil.UTF_8))
                                .addLast(new PlayerEncoder())
                                //Decoder
                                .addLast(new LineBasedFrameDecoder(512))
                                .addLast(new StringDecoder(CharsetUtil.UTF_8))
                                .addLast(new PlayerDecoder())
                                .addLast(new ChannelInboundHandlerAdapter() {
                                    @Override
                                    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                        //接收服务端发送过来的消息
                                        PlayerStatus status = (PlayerStatus) msg;
                                        if (status.getClientId() == 2) {
                                            p2States.add(status);
                                        } else {
                                            ctx.fireChannelRead(msg);
                                        }
                                    }
                                })
                                .addLast(new ChannelInboundHandlerAdapter() {
                                    @Override
                                    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                        PlayerStatus status = (PlayerStatus) msg;
                                        if (status.getClientId() == 1) {
                                            p1States.add(status);
                                        }
                                    }
                                });
                    }
                });
    }

    public static void ConnectServer(String host) {
        ChannelFuture isConnect = bootstrap.connect(host, 8080);
        isConnect.addListener((ChannelFutureListener) channelFuture -> {
            isConnected = channelFuture.isSuccess();
            channel = channelFuture.channel();
        });
    }

    public static void stopClient() {
        if (clientGroup != null) {
            clientGroup.shutdownGracefully();
        }
    }

    public static void sedMessage(parentRole parentRole) {
        channel.writeAndFlush(parentRole);
    }
}
